// Package role_service_v1
// @Author zhongxc
// @Date 2024/7/19 12:02:00
// @Desc
package role_service_v1

import (
	"context"
	"errors"
	"fmt"
	"github.com/jinzhu/copier"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"strings"
	"time"
	"unicode/utf8"
	"vben-admin/pkg/dao"
	"vben-admin/pkg/model"
	"vben-admin/pkg/repository"
	"vben-admin/pkg/svc"
	"vben-common/datatypes"
	roleService "vben-grpc-common/vben-admin/types/role.service.v1"
)

type RoleService struct {
	roleService.UnimplementedRoleServiceServer
	svcCtx           *svc.ServiceContext
	roleDao          repository.RoleRepo
	roleMenuDao      repository.RoleMenuRepo
	roleInterfaceDao repository.RoleInterfaceRepo
	roleButtonDao    repository.RoleButtonRepo
}

func NewRoleService(svcCtx *svc.ServiceContext) *RoleService {
	return &RoleService{
		svcCtx:           svcCtx,
		roleDao:          dao.NewRoleDao(svcCtx.Db),
		roleMenuDao:      dao.NewRoleMenuDao(svcCtx.Db),
		roleInterfaceDao: dao.NewRoleInterfaceDao(svcCtx.Db),
		roleButtonDao:    dao.NewRoleButtonDao(svcCtx.Db),
	}
}

func (r *RoleService) SaveOrUpdateRolePermission() error {

	return nil
}

func (r *RoleService) CreateRole(ctx context.Context, in *roleService.CreateRoleRequest) (*emptypb.Empty, error) {
	// 参数检查
	if err := r.RoleValidate(in.Name, in.Code, in.Remark); err != nil {
		return nil, status.Error(codes.InvalidArgument, err.Error())
	}

	// 角色名称、编码重复检查
	if err := r.RoleNameCodeValidateRepeat(ctx, in.Name, in.Code, 0); err != nil {
		return nil, status.Error(codes.InvalidArgument, err.Error())
	}

	var roleModel model.RoleModel
	_ = copier.Copy(&roleModel, in)
	roleModel.Status = 1
	roleModel.CreatedAt.Time = time.Now()
	roleModel.CreatedAt.Valid = true
	err := r.roleDao.CreateRole(ctx, &roleModel)
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("创建角色失败, err: %v", err))
		return nil, status.Error(codes.Internal, "创建角色失败")
	}

	// 角色关联菜单保存或更新
	err = r.roleMenuSaveOrUpdate(ctx, in.MenuIds, roleModel.Id, in.CreatedBy)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}
	return &emptypb.Empty{}, nil
}

// RoleValidate
// @Description: 角色更新前，数据校验
// @receiver r
// @param in
// @return error
func (r *RoleService) RoleValidate(name, code, remark string) error {
	// 参数校验
	if utf8.RuneCountInString(name) > 100 {
		return errors.New("角色名称不能超过200个字符")
	}
	if strings.TrimSpace(name) == "" {
		return errors.New("角色名称不能为空")
	}
	if utf8.RuneCountInString(code) > 100 {
		return errors.New("角色编码不能超过200个字符")
	}
	if strings.TrimSpace(code) == "" {
		return errors.New("角色编码不能为空")
	}
	if utf8.RuneCountInString(remark) > 500 {
		return errors.New("备注不能超过500个字符")
	}
	return nil
}

// RoleNameCodeValidateRepeat
// @Description:角色名称和编码重复检查
// @receiver r
// @param ctx
// @param roleName
// @param roleCode
// @param roleId
// @return error
func (r *RoleService) RoleNameCodeValidateRepeat(ctx context.Context, roleName string, roleCode string, roleId int64) error {
	role, err := r.roleDao.FindByName(ctx, roleName)
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("角色名称检测异常了, err: %v", err))
		return errors.New("角色名称检测异常了")
	}

	if role != nil && (roleId > 0 && role.Id != roleId) {
		return errors.New("角色名称重复")
	}

	role, err = r.roleDao.FindByCode(ctx, roleCode)
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("角色编码检测异常了, err: %v", err))
		return errors.New("角色编码检测异常了")
	}
	if role != nil && (roleId > 0 && role.Id != roleId) {
		return errors.New("角色编码重复")
	}

	return nil
}

// roleMenuSaveOrUpdate
// @Description: 角色关联菜单保存或更新
// @receiver r
// @param ctx
// @param menuIds
// @param roleId
// @param createdBy
// @return error
func (r *RoleService) roleMenuSaveOrUpdate(ctx context.Context, menuIds []int64, roleId int64, createdBy string) error {
	var menuRoleList []*model.RoleMenuModel
	for _, menuId := range menuIds {
		menuRole := &model.RoleMenuModel{
			RoleId:    roleId,
			MenuId:    menuId,
			CreatedBy: createdBy,
			CreatedAt: datatypes.Time(time.Now()),
		}
		menuRoleList = append(menuRoleList, menuRole)
	}
	if len(menuRoleList) > 0 {
		// 删除角色关联菜单
		_ = r.roleMenuDao.DeleteRoleMenuByRoleId(ctx, []int64{roleId})
		// 创建角色关联菜单
		err := r.roleMenuDao.CreateRoleMenu(ctx, menuRoleList)
		if err != nil {
			return errors.New("角色关联菜单失败")
		}
	}
	return nil
}

// UpdateRole
// @Description: 角色更新
// @receiver r
// @param ctx
// @param in
// @return *emptypb.Empty
// @return error
func (r *RoleService) UpdateRole(ctx context.Context, in *roleService.UpdateRoleRequest) (*emptypb.Empty, error) {
	// 参数检查
	if in.Id == 0 {
		return nil, status.Error(codes.InvalidArgument, "Id不能为空")
	}

	if in.Id < 0 {
		return nil, status.Error(codes.InvalidArgument, "ID参数不合法")
	}

	if err := r.RoleValidate(in.Name, in.Code, in.Remark); err != nil {
		return nil, status.Error(codes.InvalidArgument, err.Error())
	}

	// 角色名称、代码重复检查
	if err := r.RoleNameCodeValidateRepeat(ctx, in.Name, in.Code, in.Id); err != nil {
		return nil, status.Error(codes.InvalidArgument, err.Error())
	}

	roleMap := map[string]interface{}{
		"name":       in.Name,
		"code":       in.Code,
		"order_no":   in.OrderNo,
		"remark":     in.Remark,
		"status":     in.Status,
		"updated_at": time.Now(),
		"updated_by": in.UpdatedBy,
	}

	err := r.roleDao.UpdateRoleById(ctx, in.Id, roleMap)
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("更新角色失败, err: %v", err))
		return nil, status.Error(codes.Internal, "角色更新失败")
	}

	// 角色关联菜单保存或更新
	err = r.roleMenuSaveOrUpdate(ctx, in.MenuIds, in.Id, in.UpdatedBy)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}

	return &emptypb.Empty{}, nil
}

// GetRole
// @Description: 获取角色详情
// @receiver r
// @param ctx
// @param in
// @return *roleService.RoleResponse
// @return error
func (r *RoleService) GetRole(ctx context.Context, in *roleService.GetRoleRequest) (*roleService.RoleResponse, error) {
	if in.Id == 0 {
		return nil, status.Error(codes.InvalidArgument, "ID不能为空")
	}

	data, err := r.roleDao.GetRoleById(ctx, in.Id)
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("获取角色失败, err: %v", err))
		return nil, status.Error(codes.Internal, "获取角色失败")
	}

	if data == nil {
		return nil, status.Error(codes.NotFound, "找不到指定的角色")
	}

	updatedAt := ""
	if data.UpdatedAt.Valid && !data.UpdatedAt.Time.IsZero() {
		updatedAt = data.UpdatedAt.Time.Format(time.DateTime)
	}
	createdAt := ""
	if data.CreatedAt.Valid && !data.CreatedAt.Time.IsZero() {
		createdAt = data.CreatedAt.Time.Format(time.DateTime)
	}

	return &roleService.RoleResponse{
		Id:        data.Id,
		Name:      data.Name,
		Code:      data.Code,
		OrderNo:   data.OrderNo,
		Remark:    data.Remark,
		Status:    data.Status,
		CreatedAt: createdAt,
		CreatedBy: data.CreatedBy,
		UpdatedAt: updatedAt,
		UpdatedBy: data.UpdatedBy,
	}, nil
}

// DeleteRole
// @Description: 删除角色
// @receiver r
// @param ctx
// @param in
// @return *emptypb.Empty
// @return error
func (r *RoleService) DeleteRole(ctx context.Context, in *roleService.DeleteRoleRequest) (*emptypb.Empty, error) {
	if len(in.Ids) == 0 {
		return nil, status.Error(codes.InvalidArgument, "ID不能为空")
	}
	if strings.TrimSpace(in.DeletedBy) == "" {
		return nil, status.Error(codes.InvalidArgument, "删除人不能为空")
	}
	err := r.roleDao.DeleteRoleMenuTX(ctx, in.Ids, map[string]any{
		"deleted":    1,
		"deleted_by": in.DeletedBy,
		"deleted_at": time.Now(),
	})
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("删除角色失败, err: %v", err))
		return nil, status.Error(codes.Internal, "删除角色失败")
	}

	return &emptypb.Empty{}, nil
}

// GetRoleList
// @Description: 角色列表查询
// @receiver r
// @param ctx
// @param in
// @return *roleService.RoleListResponse
// @return error
func (r *RoleService) GetRoleList(ctx context.Context, in *roleService.RoleListRequest) (*roleService.RoleListResponse, error) {

	list, err := r.roleDao.GetRoleList(ctx, in.Name, in.Status)
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("角色列表查询失败, err: %v", err))
		return nil, status.Error(codes.Internal, "角色列表查询失败")
	}

	var roleSlice = make([]*roleService.RoleData, 0)
	for _, val := range list {
		var updatedAt = ""
		if val.UpdatedAt.Valid || !val.UpdatedAt.Time.IsZero() {
			updatedAt = val.UpdatedAt.Time.Format(time.DateTime)
		}
		createdAt := ""
		if val.CreatedAt.Valid && !val.CreatedAt.Time.IsZero() {
			createdAt = val.CreatedAt.Time.Format(time.DateTime)
		}
		roleData := &roleService.RoleData{
			Id:        val.Id,
			Name:      val.Name,
			Code:      val.Code,
			OrderNo:   val.OrderNo,
			Remark:    val.Remark,
			Status:    val.Status,
			CreatedAt: createdAt,
			CreatedBy: val.CreatedBy,
			UpdatedAt: updatedAt,
			UpdatedBy: val.UpdatedBy,
			Menu:      val.Menu,
		}
		roleSlice = append(roleSlice, roleData)
	}

	return &roleService.RoleListResponse{
		Data: roleSlice,
	}, nil
}

// SetRoleStatus
// @Description: 修改角色状态
// @receiver r
// @param ctx
// @param in
// @return *emptypb.Empty
// @return error
func (r *RoleService) SetRoleStatus(ctx context.Context, in *roleService.SetRoleStatusRequest) (*emptypb.Empty, error) {
	// 参数检查
	if in.Id == 0 {
		return nil, status.Error(codes.InvalidArgument, "ID不能为空")
	}
	if in.Status != 1 && in.Status != 0 {
		return nil, status.Error(codes.InvalidArgument, "状态值不合法")
	}
	// 更新角色状态
	if err := r.roleDao.UpdateRoleById(ctx, in.Id, map[string]interface{}{
		"status":     in.Status,
		"updated_at": time.Now(),
		"updated_by": in.UpdatedBy,
	}); err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("更新角色状态失败, err: %v", err))
		return nil, status.Error(codes.Internal, "更新角色状态失败")
	}

	return &emptypb.Empty{}, nil
}

func (r *RoleService) RoleBindingInterface(ctx context.Context, in *roleService.RoleBindingInterfaceRequest) (*emptypb.Empty, error) {
	if len(in.Data) == 0 {
		return nil, status.Error(codes.InvalidArgument, "提交的参数不能为空")
	}
	var roleInterfaceList = make([]*model.RoleInterfaceModel, 0)
	for _, item := range in.Data {
		var roleInterface model.RoleInterfaceModel
		_ = copier.Copy(&roleInterface, item)
		roleInterfaceList = append(roleInterfaceList, &roleInterface)
	}
	err := r.roleInterfaceDao.CreateRoleInterface(ctx, roleInterfaceList)
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("角色绑定接口失败, err: %v", err))
		return nil, status.Error(codes.Internal, "角色绑定接口失败")
	}
	return &emptypb.Empty{}, nil
}

func (r *RoleService) GetRoleInterfaceList(ctx context.Context, in *roleService.GetRoleInterfaceListRequest) (*roleService.RoleInterfaceListResponse, error) {
	list, err := r.roleInterfaceDao.GetRoleInterfaceList(ctx, in.RoleId)
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("获取角色接口列表失败, err: %v", err))
		return nil, status.Error(codes.Internal, "获取角色接口列表失败")
	}

	if len(list) > 0 {
		var roleInterfaceList = make([]*roleService.RoleInterfaceData, 0)
		for _, item := range list {
			var roleInterface roleService.RoleInterfaceData
			_ = copier.Copy(&roleInterface, item)
			roleInterfaceList = append(roleInterfaceList, &roleInterface)
		}
		return &roleService.RoleInterfaceListResponse{
			Data: roleInterfaceList,
		}, nil
	}
	return nil, nil
}

func (r *RoleService) RoleBindingButton(ctx context.Context, in *roleService.RoleBindingButtonRequest) (*emptypb.Empty, error) {
	if len(in.Data) == 0 {
		return nil, status.Error(codes.InvalidArgument, "提交的参数不能为空")
	}
	var roleButtonList = make([]*model.RoleButtonModel, 0)
	for _, item := range in.Data {
		var roleButton model.RoleButtonModel
		_ = copier.Copy(&roleButton, item)
		roleButtonList = append(roleButtonList, &roleButton)
	}
	err := r.roleButtonDao.CreateRoleButton(ctx, roleButtonList)
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("角色绑定按钮失败, err: %v", err))
		return nil, status.Error(codes.Internal, "角色绑定按钮失败")
	}
	return &emptypb.Empty{}, nil
}

func (r *RoleService) GetRoleButtonList(ctx context.Context, in *roleService.GetRoleButtonListRequest) (*roleService.RoleButtonListResponse, error) {
	list, err := r.roleButtonDao.GetRoleButtonList(ctx, in.RoleId)
	if err != nil {
		r.svcCtx.ZapLog.Error(fmt.Sprintf("获取角色按钮列表失败, err: %v", err))
		return nil, status.Error(codes.Internal, "获取角色按钮列表失败")
	}

	if len(list) > 0 {
		var roleButtonList = make([]*roleService.RoleButtonData, 0)
		for _, item := range list {
			var roleButton roleService.RoleButtonData
			_ = copier.Copy(&roleButton, item)
			roleButtonList = append(roleButtonList, &roleButton)
		}
		return &roleService.RoleButtonListResponse{
			Data: roleButtonList,
		}, nil
	}
	return nil, nil
}
